#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Final version: Generate register header files from CSV files
Supports three-column format: register name, base address, default value
"""

import csv
import os
import sys
import re
from typing import Dict, Tuple


def parse_int_value(value_str: str) -> int:
    """Parse integer value, supports hexadecimal and decimal formats"""
    value_str = str(value_str).strip().upper()
    
    if value_str.startswith('0X'):
        return int(value_str, 16)
    
    try:
        return int(value_str)
    except ValueError:
        print(f"警告: 无法解析值 '{value_str}'，使用0")
        return 0


def read_csv_file(file_path: str) -> Dict[str, Tuple[int, int]]:
    """
    Read CSV file and extract register information
    
    Returns:
        Dictionary: register name -> (base address, default value)
    """
    try:
        registers = {}
        
        with open(file_path, 'r', encoding='utf-8') as csvfile:
            reader = csv.reader(csvfile)
            # Continue updating Chinese to English...
            
            # Read title row
            try:
                headers = next(reader)
                print(f"Columns: {', '.join(headers)}")
            except StopIteration:
                print("Error: CSV file is empty")
                return registers
            
            row_num = 1
            for row in reader:
                row_num += 1
                
                if not row or len(row) < 3:
                    print(f"Line {row_num}: Skipped - insufficient columns")
                    continue
                
                reg_name = str(row[0]).strip()
                offset_addr_str = str(row[1]).strip()
                default_val_str = str(row[2]).strip()
                
                if not reg_name or reg_name.upper() == 'NAN':
                    continue
                
                offset_addr = parse_int_value(offset_addr_str)
                default_val = parse_int_value(default_val_str)
                
                registers[reg_name] = (offset_addr, default_val)
                print(f"Line {row_num}: {reg_name} @ 0x{offset_addr:08X} = 0x{default_val:08X}")
        
        return registers
        
    except Exception as e:
        print(f"Error: Failed to read file: {e}")
        sys.exit(1)


def generate_header_file(regmap:str, base_addr:int, registers: Dict[str, Tuple[int, int]], output_file: str):
    """Generate register header file"""
    try:
        with open(output_file, 'w', encoding='utf-8') as f:
            # File header
            f.write("/*\n")
            f.write(" * Register definition header file\n")
            f.write(" * Auto-generated from CSV file\n")
            f.write(" */\n\n")
            
            f.write(f"#ifndef __{regmap}_REG_H__\n")
            f.write(f"#define __{regmap}_REG_H__\n\n")
            f.write("#include <stdint.h>\n\n")
            
            # Calculate base address (use minimum address as base)
            if registers:
                f.write("/* Register base address */\n")
                f.write(f"#define {regmap}_BASE_ADDR    0x{base_addr:08X}UL\n\n")

                f.write(f"#define ReadReg32(addr)       (*(volatile uint32_t *)(addr))\n\n")
            
            # Register address definitions
            f.write("/* Register address definitions */\n")
            for reg_name, (addr, _) in sorted(registers.items()):
                clean_name = re.sub(r'[^A-Za-z0-9_]', '_', reg_name.upper())
                f.write(f"#define {regmap}_{clean_name}_ADDR    {regmap}_BASE_ADDR + 0x{addr:08X}UL\n")
            
            f.write("\n")
            
            # Register default value definitions
            f.write("/* Register default value definitions */\n")
            for reg_name, (_, default_val) in sorted(registers.items()):
                clean_name = re.sub(r'[^A-Za-z0-9_]', '_', reg_name.upper())
                f.write(f"#define {regmap}_{clean_name}_DEFAULT    0x{default_val:08X}UL\n")
            
            f.write("\n")
            
            f.write(f"int Registers_Check(void);\n")
            f.write(f"#endif /* __{regmap}_REG_H__ */\n")
        
        print(f"✓ Generated header file: {output_file}")
        
    except Exception as e:
        print(f"Error: Failed to generate header file: {e}")
        sys.exit(1)


def generate_source_file(regmap:str, registers: Dict[str, Tuple[int, int]], header_file: str, output_file: str):
    """Generate register source file"""
    try:
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write("/*\n")
            f.write(" * Register initialization source file\n")
            f.write(" * Auto-generated from CSV file\n")
            f.write(" */\n\n")
            
            f.write(f"#include \"{header_file}\"\n")
            f.write("#include <stdint.h>\n\n")
            
            # Initialization function
            f.write("/*\n")
            f.write(" * Check all registers default values\n")
            f.write(" */\n")
            f.write("int Registers_Check(void)\n")
            f.write("{\n")
            f.write("    int ret = 0;\n")
            
            for reg_name, (addr, default_val) in sorted(registers.items()):
                clean_name = re.sub(r'[^A-Za-z0-9_]', '_', reg_name.upper())
                f.write(f"    uint32_t {clean_name}_reg_val = ReadReg32({regmap}_{clean_name}_ADDR);\n")
                f.write(f"    if ({clean_name}_reg_val != {regmap}_{clean_name}_DEFAULT) {{\n")
                f.write(f"        ret = -1;\n")
                f.write("    }\n")
            
            f.write("}\n\n")
            
        
        print(f"✓ Generated source file: {output_file}")
        
    except Exception as e:
        print(f"Error: Failed to generate source file: {e}")
        sys.exit(1)


def main():
    """Main function"""
    import argparse
    
    parser = argparse.ArgumentParser(description='Generate register header and source files from CSV file')
    parser.add_argument('reg_map_name', default='REG_MAP', help='Input CSV file path')
    parser.add_argument('base_address', default='0x00000000', help='Input CSV file path')
    parser.add_argument('-f', '--csv_file', help='Input CSV file path')
    # CSV file format
    # regname, offset_addr, Default value
    # reg1,0x0,0x403
    
    parser.add_argument('-o', '--output', default='registers', help='Output filename prefix (without extension)')
    parser.add_argument('-v', '--verbose', action='store_true', help='Show detailed information')
    
    args = parser.parse_args()
    
    print("=" * 50)
    print("Register Header File Generator")
    print("=" * 50)
    
    # Read CSV file
    print(f"\nReading file: {args.csv_file}")
    registers = read_csv_file(args.csv_file)
    
    if not registers:
        print("Warning: No register definitions found")
        return
    
    print(f"\nFound {len(registers)} register definitions")
    
    # Generate files
    header_file = f"{args.output}.h"
    source_file = f"{args.output}.c"
    reg_map = (args.reg_map_name).upper()
    
    generate_header_file(reg_map, int(args.base_address, 16), registers, header_file)
    generate_source_file(reg_map, registers, header_file, source_file)
    
    print("\n" + "=" * 50)
    print("Generation Complete!")
    print("=" * 50)
    print(f"Generated files:")
    print(f"  - {header_file}")
    print(f"  - {source_file}")
    print("\nUsage instructions:")
    print(f"  1. Add {header_file} and {source_file} to your project")
    print(f"  2. Include in your code: #include \"{header_file}\"")


if __name__ == "__main__":
    main()